#!/usr/bin/env python3
import os
import sys
import json
import time
import threading
import gi
import subprocess

gi.require_version('Gtk', '3.0')
gi.require_version('Gst', '1.0')
from gi.repository import Gtk, GLib, Gst

# 初始化GStreamer
Gst.init(None)

# 应用配置
APP_NAME = "Water Alarm"
APP_VERSION = "1.0.5"
CONFIG_DIR = os.path.expanduser("~/.config/wateralarm")
CONFIG_FILE = os.path.join(CONFIG_DIR, "config.json")
DEFAULT_CONFIG = {
    "stage1_interval": 60,
    "stage1_count": 2,
    "stage2_interval": 15,
    "stage2_count": 2,
    "ringtone": "",
    "lock_screen": False
}

class SettingsDialog(Gtk.Dialog):
    def __init__(self, parent, config):
        Gtk.Dialog.__init__(self, "设置", parent, modal=True)
        self.add_buttons(Gtk.STOCK_OK, Gtk.ResponseType.OK)
        
        self.config = config.copy()
        self.set_default_size(400, 300)
        
        notebook = Gtk.Notebook()
        self.get_content_area().pack_start(notebook, True, True, 0)
        
        # 基本设置选项卡
        basic_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10)
        basic_box.set_border_width(10)
        
        # 一阶段设置
        stage1_frame = Gtk.Frame(label="一阶段提醒")
        stage1_grid = Gtk.Grid(column_spacing=10, row_spacing=5)
        stage1_grid.set_border_width(5)
        
        stage1_grid.attach(Gtk.Label(label="每"), 0, 0, 1, 1)
        self.stage1_interval = Gtk.SpinButton.new_with_range(5, 300, 5)
        self.stage1_interval.set_value(self.config["stage1_interval"])
        stage1_grid.attach(self.stage1_interval, 1, 0, 1, 1)
        stage1_grid.attach(Gtk.Label(label="秒提醒"), 2, 0, 1, 1)
        
        stage1_grid.attach(Gtk.Label(label="共提醒"), 0, 1, 1, 1)
        self.stage1_count = Gtk.SpinButton.new_with_range(1, 10, 1)
        self.stage1_count.set_value(self.config["stage1_count"])
        stage1_grid.attach(self.stage1_count, 1, 1, 1, 1)
        stage1_grid.attach(Gtk.Label(label="次"), 2, 1, 1, 1)
        
        stage1_frame.add(stage1_grid)
        basic_box.pack_start(stage1_frame, False, False, 0)
        
        # 二阶段设置
        stage2_frame = Gtk.Frame(label="二阶段提醒")
        stage2_grid = Gtk.Grid(column_spacing=10, row_spacing=5)
        stage2_grid.set_border_width(5)
        
        stage2_grid.attach(Gtk.Label(label="每"), 0, 0, 1, 1)
        self.stage2_interval = Gtk.SpinButton.new_with_range(5, 300, 5)
        self.stage2_interval.set_value(self.config["stage2_interval"])
        stage2_grid.attach(self.stage2_interval, 1, 0, 1, 1)
        stage2_grid.attach(Gtk.Label(label="秒提醒"), 2, 0, 1, 1)
        
        stage2_grid.attach(Gtk.Label(label="共提醒"), 0, 1, 1, 1)
        self.stage2_count = Gtk.SpinButton.new_with_range(0, 10, 1)
        self.stage2_count.set_value(self.config["stage2_count"])
        stage2_grid.attach(self.stage2_count, 1, 1, 1, 1)
        stage2_grid.attach(Gtk.Label(label="次（0次表示不提醒）"), 2, 1, 1, 1)
        
        stage2_frame.add(stage2_grid)
        basic_box.pack_start(stage2_frame, False, False, 0)
        
        basic_box.pack_start(Gtk.Label(), True, True, 0)
        notebook.append_page(basic_box, Gtk.Label(label="基本设置"))
        
        # 提醒铃声选项卡
        ringtone_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10)
        ringtone_box.set_border_width(10)
        
        ringtone_frame = Gtk.Frame(label="提醒铃声")
        ringtone_grid = Gtk.Grid(column_spacing=10, row_spacing=5)
        ringtone_grid.set_border_width(5)
        
        self.ringtone_entry = Gtk.Entry()
        self.ringtone_entry.set_text(self.config["ringtone"])
        ringtone_grid.attach(self.ringtone_entry, 0, 0, 1, 1)
        
        browse_btn = Gtk.Button(label="浏览...")
        browse_btn.connect("clicked", self.on_browse_clicked)
        ringtone_grid.attach(browse_btn, 1, 0, 1, 1)
        
        test_btn = Gtk.Button(label="测试铃声")
        test_btn.connect("clicked", self.on_test_ringtone)
        ringtone_grid.attach(test_btn, 2, 0, 1, 1)
        
        ringtone_frame.add(ringtone_grid)
        ringtone_box.pack_start(ringtone_frame, False, False, 0)
        
        self.lock_check = Gtk.CheckButton(label="到时锁屏")
        self.lock_check.set_active(self.config["lock_screen"])
        ringtone_box.pack_start(self.lock_check, False, False, 0)
        
        ringtone_box.pack_start(Gtk.Label(), True, True, 0)
        notebook.append_page(ringtone_box, Gtk.Label(label="提醒铃声"))
        
        self.show_all()
    
    def on_browse_clicked(self, widget):
        dialog = Gtk.FileChooserDialog(
            title="选择铃声文件", parent=self, action=Gtk.FileChooserAction.OPEN
        )
        dialog.add_buttons(
            Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
            Gtk.STOCK_OPEN, Gtk.ResponseType.OK
        )
        
        filter_audio = Gtk.FileFilter()
        filter_audio.set_name("音频文件")
        filter_audio.add_mime_type("audio/mpeg")
        filter_audio.add_mime_type("audio/wav")
        dialog.add_filter(filter_audio)
        
        response = dialog.run()
        if response == Gtk.ResponseType.OK:
            self.ringtone_entry.set_text(dialog.get_filename())
        dialog.destroy()
    
    def on_test_ringtone(self, widget):
        ringtone_path = self.ringtone_entry.get_text()
        if not ringtone_path or not os.path.exists(ringtone_path):
            dialog = Gtk.MessageDialog(
                parent=self, modal=True,
                message_type=Gtk.MessageType.ERROR,
                buttons=Gtk.ButtonsType.OK,
                text="错误"
            )
            dialog.format_secondary_text("请先选择有效的铃声文件")
            dialog.run()
            dialog.destroy()
            return
        
        try:
            pipeline = Gst.ElementFactory.make("playbin", "test-player")
            if not pipeline:
                raise Exception("无法创建播放组件")
            
            pipeline.set_property("uri", Gst.filename_to_uri(ringtone_path))
            pipeline.set_state(Gst.State.PLAYING)
            
            # 播放3秒后停止
            def stop_playback(p):
                p.set_state(Gst.State.NULL)
                return False
            
            GLib.timeout_add_seconds(3, stop_playback, pipeline)
            
        except Exception as e:
            dialog = Gtk.MessageDialog(
                parent=self, modal=True,
                message_type=Gtk.MessageType.ERROR,
                buttons=Gtk.ButtonsType.OK,
                text="播放失败"
            )
            dialog.format_secondary_text(f"无法播放铃声: {str(e)}")
            dialog.run()
            dialog.destroy()
    
    def get_config(self):
        self.config["stage1_interval"] = int(self.stage1_interval.get_value())
        self.config["stage1_count"] = int(self.stage1_count.get_value())
        self.config["stage2_interval"] = int(self.stage2_interval.get_value())
        self.config["stage2_count"] = int(self.stage2_count.get_value())
        self.config["ringtone"] = self.ringtone_entry.get_text()
        self.config["lock_screen"] = self.lock_check.get_active()
        return self.config

class AboutDialog(Gtk.AboutDialog):
    def __init__(self, parent):
        Gtk.AboutDialog.__init__(self, parent=parent, modal=True)
        self.set_program_name(APP_NAME)
        self.set_version(APP_VERSION)
        self.set_copyright("© 2023 豆包")
        self.set_comments("一个简单实用的烧开水提醒工具")
        self.set_website("https://www.doubao.com")
        self.set_website_label("豆包官网")
        self.set_logo_icon_name("dialog-information")

class AlertDialog(Gtk.Dialog):
    def __init__(self, parent, message, stop_ringtone_callback):
        Gtk.Dialog.__init__(self, "烧水提醒", parent, modal=True)
        self.stop_ringtone = stop_ringtone_callback
        self.add_buttons(Gtk.STOCK_OK, Gtk.ResponseType.OK)
        
        label = Gtk.Label(label=message)
        self.get_content_area().pack_start(label, True, True, 10)
        self.set_default_size(300, 150)
        
        # 设置窗口为顶层，确保用户能看到
        self.set_keep_above(True)
        
        self.connect("response", self.on_response)
        self.show_all()
    
    def on_response(self, dialog, response_id):
        if response_id == Gtk.ResponseType.OK:
            # 调用回调函数停止铃声
            self.stop_ringtone()
        self.destroy()

class WaterAlarmWindow(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self, title=APP_NAME)
        self.set_default_size(400, 200)
        
        self.config = self.load_config()
        self.audio_pipeline = None
        self.ringtone_playing = False  # 音频播放状态标记
        self.alert_window = None  # 提醒窗口引用
        
        # 状态变量
        self.is_running = False
        self.current_stage = 1
        self.remaining_time = 0
        self.stage_counter = 0
        self.stop_clicks = 0
        self.timer_thread = None
        
        self.create_ui()
    
    def create_ui(self):
        menubar = Gtk.MenuBar()
        
        # 文件菜单
        file_menu = Gtk.Menu()
        file_menu_item = Gtk.MenuItem(label="文件")
        file_menu_item.set_submenu(file_menu)
        
        settings_item = Gtk.MenuItem(label="设置")
        settings_item.connect("activate", self.on_settings_clicked)
        file_menu.append(settings_item)
        
        exit_item = Gtk.MenuItem(label="退出")
        exit_item.connect("activate", self.on_exit_clicked)
        file_menu.append(exit_item)
        
        # 帮助菜单
        help_menu = Gtk.Menu()
        help_menu_item = Gtk.MenuItem(label="帮助")
        help_menu_item.set_submenu(help_menu)
        
        about_item = Gtk.MenuItem(label="关于")
        about_item.connect("activate", self.on_about_clicked)
        help_menu.append(about_item)
        
        menubar.append(file_menu_item)
        menubar.append(help_menu_item)
        
        # 主布局
        main_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10)
        main_box.pack_start(menubar, False, False, 0)
        
        # 进度条区域
        progress_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
        progress_box.set_border_width(10)
        
        self.progress_bar = Gtk.ProgressBar()
        self.progress_bar.set_fraction(1.0)
        
        # 设置进度条颜色
        style_context = self.progress_bar.get_style_context()
        provider = Gtk.CssProvider()
        css = """
        progressbar progress {
            background-color: #0078d7;
            min-height: 5px;
            min-width: 5px;
        }
        """
        provider.load_from_data(css.encode())
        style_context.add_provider(
            provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
        )
        
        progress_box.pack_start(self.progress_bar, True, True, 0)
        
        self.time_label = Gtk.Label(label="准备就绪")
        self.time_label.set_halign(Gtk.Align.CENTER)
        progress_box.pack_start(self.time_label, False, False, 0)
        
        main_box.pack_start(progress_box, True, True, 0)
        
        # 按钮区域
        btn_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10)
        btn_box.set_homogeneous(True)
        btn_box.set_border_width(10)
        
        self.start_btn = Gtk.Button(label="开始计时")
        self.start_btn.connect("clicked", self.on_start_clicked)
        btn_box.pack_start(self.start_btn, True, True, 0)
        
        self.stop_btn = Gtk.Button(label="停止计时")
        self.stop_btn.connect("clicked", self.on_stop_clicked)
        self.stop_btn.set_sensitive(False)
        btn_box.pack_start(self.stop_btn, True, True, 0)
        
        main_box.pack_start(btn_box, False, False, 0)
        
        self.add(main_box)
    
    def load_config(self):
        try:
            if not os.path.exists(CONFIG_DIR):
                os.makedirs(CONFIG_DIR)
            
            config = {}
            if os.path.exists(CONFIG_FILE):
                with open(CONFIG_FILE, 'r') as f:
                    config = json.load(f)
            
            for key, value in DEFAULT_CONFIG.items():
                if key not in config:
                    config[key] = value
            
            with open(CONFIG_FILE, 'w') as f:
                json.dump(config, f, indent=4)
            
            return config
        except Exception as e:
            print(f"加载配置失败: {e}")
            return DEFAULT_CONFIG.copy()
    
    def save_config(self):
        try:
            with open(CONFIG_FILE, 'w') as f:
                json.dump(self.config, f, indent=4)
        except Exception as e:
            print(f"保存配置失败: {e}")
    
    def on_settings_clicked(self, widget):
        dialog = SettingsDialog(self, self.config)
        response = dialog.run()
        
        if response == Gtk.ResponseType.OK:
            self.config = dialog.get_config()
            self.save_config()
        
        dialog.destroy()
    
    def on_about_clicked(self, widget):
        dialog = AboutDialog(self)
        dialog.run()
        dialog.destroy()
    
    def on_exit_clicked(self, widget):
        self.is_running = False
        self.stop_ringtone()
        Gtk.main_quit()
    
    def on_start_clicked(self, widget):
        if not self.is_running:
            self.is_running = True
            self.current_stage = 1
            self.stage_counter = 0
            self.remaining_time = self.config["stage1_interval"]
            self.start_btn.set_sensitive(False)
            self.stop_btn.set_sensitive(True)
            self.stop_clicks = 0
            
            self.update_progress()
            
            self.timer_thread = threading.Thread(target=self.timer_loop)
            self.timer_thread.daemon = True
            self.timer_thread.start()
    
    def on_stop_clicked(self, widget):
        self.stop_clicks += 1
        
        if self.stop_clicks >= 2:
            self.reset_timer()
            self.stop_clicks = 0
        else:
            self.is_running = False
            self.start_btn.set_sensitive(True)
            self.time_label.set_text(f"已暂停 - 剩余 {self.remaining_time} 秒")
    
    def reset_timer(self):
        self.is_running = False
        self.stop_ringtone()
        self.progress_bar.set_fraction(1.0)
        self.time_label.set_text("准备就绪")
        self.start_btn.set_sensitive(True)
        self.stop_btn.set_sensitive(False)
    
    def update_progress(self):
        if self.current_stage == 1:
            total_time = self.config["stage1_interval"]
        else:
            total_time = self.config["stage2_interval"]
            
        fraction = self.remaining_time / total_time if total_time > 0 else 0
        self.progress_bar.set_fraction(fraction)
        self.time_label.set_text(f"倒数 {self.remaining_time} 秒")
    
    def show_alert(self, message):
        # 如果已有提醒窗口则关闭
        if self.alert_window:
            self.alert_window.destroy()
        
        # 创建新提醒窗口，传入停止铃声的回调函数
        self.alert_window = AlertDialog(self, message, self.stop_ringtone)
        self.alert_window.run()
        self.alert_window = None  # 窗口关闭后重置引用
    
    def stop_ringtone(self):
        """停止铃声播放（线程安全版本）"""
        if self.ringtone_playing and self.audio_pipeline:
            try:
                self.audio_pipeline.set_state(Gst.State.NULL)
                self.ringtone_playing = False
                self.audio_pipeline = None
            except Exception as e:
                print(f"停止铃声失败: {e}")
    
    def play_ringtone(self):
        """播放铃声（线程安全版本）"""
        # 确保不同时播放多个铃声
        if self.ringtone_playing:
            return
        
        if not self.config["ringtone"] or not os.path.exists(self.config["ringtone"]):
            print("未设置有效的铃声文件")
            return
        
        try:
            # 创建播放组件
            self.audio_pipeline = Gst.ElementFactory.make("playbin", "audio-player")
            if not self.audio_pipeline:
                print("无法创建播放组件 - 可能缺少GStreamer插件")
                return
            
            # 设置播放文件
            self.audio_pipeline.set_property("uri", Gst.filename_to_uri(self.config["ringtone"]))
            
            # 开始播放
            self.audio_pipeline.set_state(Gst.State.PLAYING)
            self.ringtone_playing = True
            
            # 监控播放状态（修复了bus.pop()的参数问题）
            def monitor_playback():
                if not self.ringtone_playing or not self.audio_pipeline:
                    return False
                
                bus = self.audio_pipeline.get_bus()
                # 修复：pop()方法不需要参数，使用timed_pop_filtered()替代
                msg = bus.timed_pop_filtered(
                    0,  # 不等待，立即返回
                    Gst.MessageType.ERROR | Gst.MessageType.EOS
                )
                
                if msg:
                    if msg.type == Gst.MessageType.ERROR:
                        err, debug = msg.parse_error()
                        print(f"播放错误: {err.message}")
                    self.stop_ringtone()
                    return False
                
                # 继续监控
                return True
            
            # 每100ms检查一次播放状态
            GLib.timeout_add(100, monitor_playback)
            
        except Exception as e:
            print(f"播放铃声失败: {e}")
            self.ringtone_playing = False
            self.audio_pipeline = None
    
    def lock_screen(self):
        try:
            subprocess.run(["xflock4"], check=True)
        except Exception as e:
            print(f"锁屏失败: {e}")
    
    def timer_loop(self):
        while self.is_running:
            time.sleep(1)
            self.remaining_time -= 1
            GLib.idle_add(self.update_progress)
            
            if self.remaining_time <= 0:
                self.stage_counter += 1
                
                # 播放铃声（在主线程执行）
                GLib.idle_add(self.play_ringtone)
                
                # 显示提醒信息
                if self.current_stage == 1:
                    msg = f"第一阶段提醒 ({self.stage_counter}/{self.config['stage1_count']})"
                else:
                    msg = f"第二阶段提醒 ({self.stage_counter}/{self.config['stage2_count']})"
                
                # 显示提醒窗口（在主线程执行）
                GLib.idle_add(self.show_alert, msg)
                
                # 等待用户处理提醒后再继续
                while self.ringtone_playing and self.is_running:
                    time.sleep(0.5)
                
                # 检查阶段转换
                if self.current_stage == 1:
                    if self.stage_counter >= self.config["stage1_count"]:
                        if self.config["stage2_count"] > 0:
                            self.current_stage = 2
                            self.stage_counter = 0
                            self.remaining_time = self.config["stage2_interval"]
                        else:
                            self.is_running = False
                            GLib.idle_add(self.update_progress)
                            GLib.idle_add(self.time_label.set_text, "计时结束")
                            
                            if self.config["lock_screen"]:
                                GLib.idle_add(self.lock_screen)
                                
                            GLib.idle_add(self.start_btn.set_sensitive, True)
                            GLib.idle_add(self.stop_btn.set_sensitive, False)
                            break
                    else:
                        self.remaining_time = self.config["stage1_interval"]
                else:
                    if self.stage_counter >= self.config["stage2_count"]:
                        self.is_running = False
                        GLib.idle_add(self.update_progress)
                        GLib.idle_add(self.time_label.set_text, "计时结束")
                        
                        if self.config["lock_screen"]:
                            GLib.idle_add(self.lock_screen)
                            
                        GLib.idle_add(self.start_btn.set_sensitive, True)
                        GLib.idle_add(self.stop_btn.set_sensitive, False)
                        break
                    else:
                        self.remaining_time = self.config["stage2_interval"]

if __name__ == "__main__":
    import locale
    locale.setlocale(locale.LC_ALL, '')
    
    if "GST_PLUGIN_PATH" not in os.environ:
        os.environ["GST_PLUGIN_PATH"] = "/usr/lib/x86_64-linux-gnu/gstreamer-1.0:/usr/lib/gstreamer-1.0"
    
    window = WaterAlarmWindow()
    window.connect("destroy", lambda w: Gtk.main_quit())
    window.show_all()
    Gtk.main()
